
#pragma once

template<typename TUnknown>
class AutoUnk
{

public:

	AutoUnk() : m_Unknown(NULL)
	{

	}

	AutoUnk(TUnknown pUnk) : m_Unknown(pUnk)
	{
		ASSERT(Validate(pUnk));
	}

	~AutoUnk()
	{
		if (m_Unknown)
			m_Unknown->Release();
	}

	TUnknown Push(TUnknown pUnk)
	{
		ASSERT(Validate(pUnk));

		if (m_Unknown)
			return NULL;

		m_Unknown = pUnk;
		return m_Unknown;
	}

	TUnknown Pop(VOID)
	{
		TUnknown t = m_Unknown;
		m_Unknown = NULL;
		return t;
	}

	VOID Kill(VOID)
	{
		if (m_Unknown)
		{
			m_Unknown->Release();
			m_Unknown = NULL;
		}
	}

	LONG GetRef(VOID)
	{
		if (!m_Unknown)
			return 0L;

		m_Unknown->AddRef();
		return m_Unknown->Release();
	}

	operator TUnknown & ()
	{
		return m_Unknown;
	}

	operator LPVOID * ()
	{
		return reinterpret_cast<LPVOID *>(&m_Unknown);
	}

	operator bool ()
	{
		return m_Unknown ? true : false;
	}

	AutoUnk &operator = (TUnknown pUnk)
	{
		ASSERT(Validate(pUnk));
		Kill();
		VERIFY(Push(pUnk));
		return *this;
	}

	BOOL operator ! () const
	{
		return m_Unknown ? FALSE : TRUE;
	}

	TUnknown *operator & ()
	{
		return &m_Unknown;
	}

	TUnknown operator -> ()
	{
		return	m_Unknown;
	}

private:

#ifdef _DEBUG
	BOOL Validate(TUnknown pUnk)
	{
		if (!pUnk)
			return TRUE;

		LPUNKNOWN pUnknown = dynamic_cast<LPUNKNOWN>(pUnk);
		if (!pUnknown)
			return FALSE;

		return TRUE;
	}
#endif

	TUnknown	m_Unknown;

};
